/*
 * Copyright (c) 2003-2010, Live Media Pty. Ltd.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without modification, are permitted
 * provided that the following conditions are met:
 *
 *  1. Redistributions of source code must retain the above copyright notice, this list of
 *     conditions and the following disclaimer.
 *  2. Redistributions in binary form must reproduce the above copyright notice, this list of
 *     conditions and the following disclaimer in the documentation and/or other materials
 *     provided with the distribution.
 *  3. Neither the name of Live Media nor the names of its contributors may be used to endorse
 *     or promote products derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER
 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

package com.colony.networkvm.machine;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import com.argot.TypeException;
import com.argot.TypeInputStream;
import com.argot.TypeLibraryReader;
import com.argot.TypeLibraryWriter;
import com.argot.TypeMap;
import com.argot.TypeOutputStream;
import com.argot.TypeReader;
import com.argot.TypeWriter;
import com.argot.common.UInt16;
import com.colony.remote.RemoteException;

public class NvmHeap
{
	public static final String TYPENAME = "nvm.heap";
	
    public ArrayList _list;
	public int _count;
	public int _free;
	
	public NvmHeap()
	{
		_list = new ArrayList();
		_count = 0;
		_free = 0;
	}
	
	public NvmHeap( ArrayList list, int count, int free )
	{
		_list = list;
		_count = count;
		_free = free;
	}
	
	public int addObject( int id, Object o )
	{
		NvmHeapElement element = new NvmHeapElement( id, o);
		_list.add( element );
		_count++;
		return _list.indexOf(element);
	}
	
	public Object removeObject( int index ) 
	throws RemoteException
	{
		NvmHeapElement nhe = (NvmHeapElement) _list.remove(index);
		if ( nhe == null )
		{
			throw new RemoteException("item not found on heap");
		}
		_list.add(index,EMPTY);
		_count--;
		_free++;
		return nhe.o;
	}
	
	public Object getObject( int index ) 
	throws RemoteException
	{
		NvmHeapElement nhe = (NvmHeapElement) _list.get(index);
		if ( nhe == null )
		{
			throw new RemoteException("item not found on heap");
		}
		return nhe.o;		
	}
	
	public int getObjectId( int index )
	throws RemoteException
	{
		NvmHeapElement nhe = (NvmHeapElement) _list.get(index);
		if ( nhe == null )
		{
			throw new RemoteException("item not found on heap");
		}
		return nhe.id;			
	}

	public void storeHeapObject(int index, int id, Object o)
	{
        if ( _list.size() < index )
        {
        	for (int x=_list.size(); x<index; x++ )
        	{
        		_list.add( EMPTY );
        	}
        }
        
        _list.set( index, new NvmHeapElement( id, o ));
	}

	
	private static final NvmHeapElement EMPTY = new NvmHeapElement(1,null);

	public static class NvmHeapTypeWriter
	implements TypeWriter
	{
		private TypeWriter _uint16;
		private TypeWriter _empty;
		int _emptyId;
		
		private NvmHeapTypeWriter(TypeMap map) 
		throws TypeException
		{
			_uint16 = map.getWriter(map.getStreamId(UInt16.TYPENAME));
			_emptyId = map.getStreamId("empty");
			_empty = map.getWriter(_emptyId);
		}
		
	    public void write(TypeOutputStream out, Object o) throws TypeException, IOException
	    {
			NvmHeap s = (NvmHeap)o;
			List list = s._list;
			
			_uint16.write( out, new Integer( list.size() ));
			for ( int x=0; x<list.size();x++ )
			{
				NvmHeapElement item = (NvmHeapElement) list.get(x);
				if ( item == EMPTY )
				{
					_uint16.write( out, new Integer( _emptyId ));
					_empty.write( out, item.o );
				}
				else
				{
					int id = out.getTypeMap().getStreamId( item.id );
					_uint16.write( out, new Integer( id ));
					out.writeObject( id, item.o );
				}
			}
	    }
	}
	
	public static class NvmHeapTypeLibraryWriter
	implements TypeLibraryWriter
	{
		public TypeWriter getWriter(TypeMap map) 
		throws TypeException 
		{
			return new NvmHeapTypeWriter(map);
		}	
	}

	private static class NvmHeapTypeReader
	implements TypeReader
	{
		private TypeReader _uint16;
		int _emptyId;
		
		private NvmHeapTypeReader(TypeMap map) 
		throws TypeException
		{
			_uint16 = map.getReader(map.getStreamId(UInt16.TYPENAME));
			_emptyId = map.getStreamId("empty");
		}
		
	    public Object read(TypeInputStream in) throws TypeException, IOException
	    {
			int free = 0;
			int count = 0;
	
	        Integer size = (Integer) _uint16.read(in);
	        ArrayList list = new ArrayList();
	        for ( int x=0; x<size.intValue(); x++ )
	        {
	        	Integer id = (Integer) _uint16.read(in);
	        	Object o = in.readObject( id.intValue());
	        	if ( id.intValue() == _emptyId )
	        	{
	        		list.add( EMPTY );
					free++;		
				}
	        	else
	        	{
	        		int sysid = in.getTypeMap().getDefinitionId( id.intValue() );
	        		list.add( new NvmHeapElement( sysid, o));
					count++;
	        	}
	        }
			return new NvmHeap( list, count, free );
	    }
	}
	
	public static class NvmHeapTypeLibraryReader
	implements TypeLibraryReader
	{

		public TypeReader getReader(TypeMap map) 
		throws TypeException 
		{
			return new NvmHeapTypeReader(map);
		}
		
	}
	
}
